#include "graph.h";

int graph_addVertex(int nodeA, int nodeB, Graph *graph)
{
    int res = 0;
    if(matrix_addVertex(nodeA, nodeB, &graph->adjacency) == 1)
    {
        graph->vertices++;
        res = 1;
    }
    
    return res;
    
}

int graph_removeVertex(int nodeA, int nodeB, Graph *graph)
{
    int res = 0;
    if(matrix_removeVertex(nodeA, nodeB, &graph->adjacency) == 1)
    {
        graph->vertices--;
        res = 1;
    }
    
    return res;
}

int graph_addNode(Graph *graph)
{
    int res = 0;
    if(matrix_addNode(&(graph->adjacency)) == 1)
    {
        graph->nodes++;
        res = 1;
    }
    
    return res;
}

int graph_removeNode(int node, Graph *graph)
{
    int res = 0;
    printf("Node : %d", graph->adjacency.size);
    if(matrix_removeNode(node, &(graph->adjacency)) == 1)
    {
        graph->nodes--;
        res = 1;
    }
    
    return res;
}

void graph_printGraphInfo(Graph *graph)
{
    printf("Nombre de sommets : %d\nNombres d'arêtes : %d\n\n", graph->nodes, graph->vertices);
    printf("Matrice d'adjacence :\n");
    printMatrix(&(graph->adjacency));
    graph_printNodesNames(graph);
}

// Affiche le nom des sommets
void graph_printNodesNames(Graph *graph)
{
    if(graph->nodesName != NULL)
    {
        int i;
        printf("Nom des sommets :\n");
        for(i = 0;i < graph->nodes;i++)
            printf("%c : %s\n", i + 'A', graph->nodesName[i]);
    }
    
    printf("\n");
}

Matrix graph_Warshall(Graph graph)
{
    Matrix res;
    
    int n = graph.nodes;
    
    res.size = graph.nodes;
    res.table = matrix_createTable(n);
    
    matrix_cloneTable(graph.adjacency.table, res.table, n);
    
    int i,j,k;
    
    int nombre_action = 8;
    
    for(k=0;k<n;k++){
     for(i=0;i<n;i++){
      for(j=0;j<n;j++){
       res.table[i][j]=max(res.table[i][j],res.table[i][k]&&res.table[k][j]); 
       nombre_action++;}}}
    
     printf("-- Pour information cette fonction a effectue %d actions (a ajouter aux nombres d'actions faites par les fonctions appelees dans celle-ci) --\n\n", nombre_action+1);
  
    return res;
}

void graph_BFS(int** adj,int *visited,int start, int size)
{
        int *q = (int *)malloc(size * sizeof(int));
	int rear=-1,front=-1,i;
	q[++rear]=start;
	visited[start]=1;
	int nombre_action = 4;
	while(rear != front)
	{
		start = q[++front];
			
                printf(" -> %c ",start+65); 

		for(i=0;i<size;i++)
		{
			if(adj[start][i] && !visited[i])
			{
				q[++rear]=i;
				visited[i]=1;
			}
			nombre_action++;
		}
	}
	  printf("-- Pour information cette fonction a effectue %d actions (a ajouter aux nombres d'actions faites par les fonctions appelees dans celle-ci) --\n\n", nombre_action+1);
  
}

void graph_DFS(int **adj,int n,int *visited,int u,int *queue, int r){
 
    int v;
    visited[u]=1;
    int nombre_action = 2;
    for(v = 0;v < n; v++)
    {
        if(adj[u][v] == 1 && visited[v] == 0)
        {
            queue[++r] = v;
            graph_DFS(adj,n,visited,v,queue, r);
        }
        nombre_action++;
    }
    printf("-- Pour information cette fonction a effectue %d actions (a ajouter aux nombres d'actions faites par les fonctions appelees dans celle-ci) --\n\n", nombre_action+1);
  
}


void printDFS(int **adj,int size,int *queue){
    int i,source, *s;
    s = (int *)malloc(sizeof(int)*size);
    printf("Noeud racine (nombre inf. a %d) : ",size);
    scanf("%d",&source);
     
    for(i=0;i<size;i++)
        s[i]=0;
     
    queue[0]=source;
    graph_DFS(adj,size,s,source,queue, 0);
     
    for(i=0;i<size;i++)
    {
        if(s[i]!=0)
        {
        printf(" -> %c ",queue[i] + 65);
        }
    }
}

/*
* A finir
*/

/*void malgrange(Matrix *matrix){
    
    printf("\n");
    int r,i,z,y=0;
    int s[100];
    llist nodes = NULL;
    int* visited = malloc(sizeof(int)*(matrix->size));
    llist* cc = malloc(sizeof(llist)*(matrix->size));
    llist c;
    for (i = 0; i < matrix->size; i++){
        nodes = ajouterEnFin(nodes,i);
        s[i]=0;
    }
    for (i = 0; i < matrix->size; i++){
        nodes = ajouterEnFin(nodes,i);
        s[i]=0;
    }
    while(!estVide(nodes)){
        r = 0;
        int randomNode = element_i(nodes,rand()%(nombreElements(nodes)-1))->val;
        visited[0]=randomNode;
        //dfs(matrix->table,matrix->size,s,randomNode,visited);
        c = malloc(sizeof(llist)*(r));
        printf("{");

        for(i=0;i<=r;i++)
        {
            c = ajouterEnFin(c,visited[i]);
            nodes = supprimerElement(nodes,visited[i]);
            
            if(i==r)
                printf("%c",visited[i]+'a');
            else
                printf("%c, ",visited[i]+'a');
        }
        printf("} ");
    }
    printf("\n\n");
}*/

void readCSVFile(char *fileName, Graph *graph)
{
    FILE *file = NULL;
    char *line = NULL;
    char **nodesNames = NULL;
    char **splitTable = NULL;
    char c;
    size_t len = 0;
    int isNodeNamed = FALSE;
    int delimiter = '\r';
    int i = 0, j = 0, nbNodes = 0, readNumber = 0, nbVertices = 0;
    
    file = fopen(fileName, "r");
    
    // Si le fichier n'a pas été trouvé
    if(file == NULL)
    {
        printf("Erreur lors de l'ouverture du fichier");
        return(EXIT_FAILURE);
    }
    
    // Nombre de sommets dans la matrices et sauvegarde de leurs noms
    //TODO: Récupérer les chaines de noms, non fonctionnel pour le moment
    getdelim(&line, &len, delimiter, file);
    splitTable = str_split(line, ";");

    while(*splitTable){
        nbNodes++;
        splitTable++;
    }
    splitTable -= nbNodes;
    

    nodesNames = malloc(nbNodes * sizeof(char*));
    for (i = 0; i < nbNodes; i++)
        nodesNames[i] = malloc((100) * sizeof(char));

    i=0;
    while(*splitTable){
        nodesNames[i] = *splitTable;
        splitTable++;
        i++;
    }
    i=0;
    
    graph->nodesName = nodesNames;
    graph->nodes = nbNodes;
    graph->adjacency.size = nbNodes;
    graph->adjacency.table = matrix_createTable(nbNodes);
    
    // Lecture du fichier
    while((getdelim(&line, &len, delimiter, file)) != -1)
    {
        // Remplacement du caractère \r par \n
        line = str_replace(line, '\r', '\n');
        
        // Split de la ligne suivant le caractère 
        splitTable = str_split(line, ";");
        
        while(*splitTable)
        {
            if(str_isInteger(*splitTable) == TRUE)
            {
                readNumber = strtol(*splitTable, (char**)NULL, 10);
                
                graph->adjacency.table[i][j++] = readNumber;
                
                if(readNumber == 1)
                {
                    if(i == j)
                        nbVertices += 2;
                    else
                        nbVertices++;
                }
            }
            splitTable++;
        }
        
        i++;
        j = 0;
    }
    
    graph->vertices = nbVertices / 2;
    
    fclose(file);
}

// Génère une matrice aléatoire
void generateRandomMatrix(Graph *graph)
{
    Matrix matrix;
    int nbNodes, nbVertices, maxVertex;
    int **tab;
    int nodeA, nodeB, returnScan, boolVertices = 0;
    srand(time(NULL));
    
    // Renseignement
    printf("Nombre de sommets ? : ");
    while (scanf("%d", &nbNodes) != 1) {
        clear_stream(stdin);
        printf("Valeur invalide. Réessayer : ");
        fflush(stdout);
    }
        
    maxVertex = ((nbNodes*(nbNodes - 1))/2) + nbNodes;
    
    printf("Nombre d'aretes (max : %d) ? ", maxVertex);

    while (boolVertices == FALSE )
    {
        returnScan = scanf("%d", &nbVertices);
        if(returnScan != 1 || (nbVertices < 0 || nbVertices > maxVertex))
        {
            clear_stream(stdin);
            printf("Valeur invalide. Réessayer : ");
            fflush(stdout);
        }
        else
            boolVertices = TRUE;
    }
    // Création du tableau
    tab = matrix_createTable(nbNodes);
    
    // Assignation
    matrix.size = nbNodes;

    matrix.table = tab;

    graph->nodes = nbNodes;
    graph->vertices = nbVertices;
    
    while(nbVertices != 0)
    {
        // 2 sommets aléatoires
        nodeA = (rand() % nbNodes);
        nodeB = (rand() % nbNodes);
        
        // Si il n'y a pas d'arête entre les deux sommets
        if(matrix_existVertex(nodeA, nodeB, &matrix) == FALSE)
        {
            // On ajoute une arête
            matrix_addVertex(nodeA, nodeB, &matrix);
            nbVertices--;
        }
        
    }
    
    graph->adjacency = matrix;
}